//
//  StorageManagers.m
//  XinYiGou
//
//  Created by Angel_Yan on 2017/4/13.
//  Copyright © 2017年 Angel_Yan. All rights reserved.
//

#import "StorageManagers.h"



#define kConfigPlistFileName    @"config.plist"
#define kMaxImageWidthDefault   2048
#define kCompressionQualityDefault  0.8f


@implementation FileUtils

NSString *_documentDirectoryPath = nil;
NSString *_cacheDirectoryPath = nil;

#pragma mark - File Path
+ (NSString *)documentsDirectory {
	if ( ! _documentDirectoryPath) {
		NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
		_documentDirectoryPath = [paths objectAtIndex:0];
	}
	return _documentDirectoryPath;
}

+ (NSString *)tmpDirectory {
	return NSTemporaryDirectory();
}

+ (NSString *)cacheDirectory {
	if ( ! _cacheDirectoryPath) {
		NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
		_cacheDirectoryPath = [paths objectAtIndex:0];
	}
	return _cacheDirectoryPath;
}

+ (NSString *)subDocumentsPath:(NSString *)subFilepath {
	return [[self documentsDirectory] stringByAppendingPathComponent:subFilepath];
}

+ (NSString *)ensureParentDirectory:(NSString *)filepath {
	NSString *parentDirectory = [filepath stringByDeletingLastPathComponent];
	BOOL isDirectory;
	if (( ! [[NSFileManager defaultManager] fileExistsAtPath:parentDirectory isDirectory:&isDirectory]) || ( ! isDirectory)) {
		[[NSFileManager defaultManager] createDirectoryAtPath:parentDirectory withIntermediateDirectories:YES attributes:nil error:NULL];
	}
	return filepath;
}

+ (NSString *)ensureDirectory:(NSString *)filepath {
	BOOL isDirectory;
	if (( ! [[NSFileManager defaultManager] fileExistsAtPath:filepath isDirectory:&isDirectory]) || ( ! isDirectory)) {
		[self ensureParentDirectory:filepath];
		[[NSFileManager defaultManager] createDirectoryAtPath:filepath withIntermediateDirectories:YES attributes:nil error:NULL];
	}
	return filepath;
}

+ (void)saveImage:(UIImage *)image toFile:(NSString *)filePath {
	[self saveImage:image toFile:filePath maxWidth:kMaxImageWidthDefault];
}

+ (void)saveImage:(UIImage *)image toFile:(NSString *)filePath maxWidth:(CGFloat)maxWidth {
	NSData *imageData;
	imageData = UIImageJPEGRepresentation(image, kCompressionQualityDefault);
	[self ensureParentDirectory:filePath];
	[imageData writeToFile:filePath atomically:YES];
}

+ (NSString *)saveImageWithTimestampName:(UIImage *)image {
	long long timestamp = [[NSDate date] timeIntervalSince1970] * 1000;
	NSString *picturePath = [[FileUtils tmpDirectory] stringByAppendingPathComponent:[NSString stringWithFormat:@"%lld.jpg", timestamp]];
	[self saveImage:image toFile:picturePath];
	return picturePath;
}

+ (NSString *)convertString:(NSString *)string fromFormat:(NSString *)oldFormat toFormat:(NSString *)newFormat {
	NSDate *date = [self dateFromString:string withFormat:oldFormat];
	return [[self dateFormaterWithFormat:newFormat] stringFromDate:date];
}

+ (NSDate *)dateFromString:(NSString *)string withFormat:(NSString *)format {
	return [[self dateFormaterWithFormat:format] dateFromString:string];
}

#pragma mark - private metholds

+ (NSDateFormatter *)dateFormaterWithFormat:(NSString *)formatString {
	NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
	[dateFormatter setDateFormat:formatString];
	return dateFormatter;
}


@end



#define kDatabaseFileName   @"scsd.sqlite"
#define kSettingsFileName   @"settings.archive"
#define kLbsInfoFileName    @"lbs.archive"
#define kUserInfoFileName   @"userInfo.archive"

#define kCommonDirName      @"common/"

#define kAudioDirName       @"audio/"
#define kVideoDirName       @"video/"
#define kPictureDirName     @"pic/"
#define kUploadPicsDirName  @"uploading_pictures/"

@interface StorageManagers ()

@property (nonatomic, strong) NSString *userDir;
@property (nonatomic, strong) NSDictionary *appConfigDictionary;

@end


@implementation StorageManagers

+ (instancetype)sharedInstance {
	DEFINE_SHARED_INSTANCE_USING_BLOCK(^ {
		return [[self alloc] init];
	})
}

- (id)init {
	self = [super init];
	if (self) {
		self.userDir = kCommonDirName;
	}
	return self;
}

- (void)setUserId:(NSString *)userId {
	if ( ![NSString isNilOrEmpty:userId]) {
		self.userDir = [userId copy];
	}
	else {
		self.userDir = kCommonDirName;
	}
	
	[self ensureAllDirectories];
}

#pragma mark - 文件和目录路径

- (NSString *)documentsDirectoryPath {
	return [FileUtils documentsDirectory];
}

- (NSString *)documentsDirectoryPathByUser {
	return [[self documentsDirectoryPath] stringByAppendingPathComponent:self.userDir];
}

- (NSString *)documentsDirectoryPathCommon {
	return [[self documentsDirectoryPath] stringByAppendingPathComponent:kCommonDirName];
}

- (NSString *)databaseFilePath {
	return [[self documentsDirectoryPathByUser] stringByAppendingPathComponent:kDatabaseFileName];
}

- (NSString *)settingsFilePath {
	return [[self documentsDirectoryPathCommon] stringByAppendingPathComponent:kSettingsFileName];
}

- (NSString *)documentsDirectoryLogPath {
	return [[self documentsDirectoryPath] stringByAppendingPathComponent:@"Log/"];
}

- (NSString *)cachesDirectoryPath {
	return [FileUtils cacheDirectory];
}

- (NSString *)cachesDirectoryPathByUser {
	return [[self cachesDirectoryPath] stringByAppendingPathComponent:self.userDir];
}

- (NSString *)cachesDirectoryPathCommon {
	return [[self cachesDirectoryPath] stringByAppendingPathComponent:kCommonDirName];
}

- (NSString *)lbsInfoFilePath {
	return [[self cachesDirectoryPathCommon] stringByAppendingPathComponent:kLbsInfoFileName];
}

- (NSString *)userInfoFilePath {
	return [[self cachesDirectoryPathByUser] stringByAppendingPathComponent:kUserInfoFileName];
}

- (NSString *)audioDirectoryPath; {
	return [[self cachesDirectoryPathByUser] stringByAppendingPathComponent:kAudioDirName];
}

- (NSString *)videoDirectoryPath {
	return [[self cachesDirectoryPathByUser] stringByAppendingPathComponent:kVideoDirName];
}

- (NSString *)chatPictureDirectoryPath {
	return [[self cachesDirectoryPathByUser] stringByAppendingPathComponent:kPictureDirName];
}

- (NSString *)tmpDirectoryPath {
	return [FileUtils tmpDirectory];
}

- (NSString *)uploadingPictureDirectoryPath {
	return [[self tmpDirectoryPath] stringByAppendingPathComponent:kUploadPicsDirName];
}

#pragma mark - 配置文件存取
/**
 *  设置config某个key对应的value
 *
 *  @param value
 *  @param key
 */
- (void)setConfigValue:(NSObject *)value forKey:(NSString *)key {
	[self setConfigWithValuesAndKeys:value, key, nil];
}
/**
 *  设置config的通用方法
 *  overwrite = yes
 *
 *  @param firstObject object+key...
 */
- (void)setConfigWithValuesAndKeys:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION {
	NSMutableArray *keys = [NSMutableArray array];
	NSMutableArray *values = [NSMutableArray array];
	
	va_list args;
	va_start(args, firstObject);
	for (id value = firstObject; value != nil; value = va_arg(args, id)) {
		id key = va_arg(args, id);
		[values addObject:value];
		[keys addObject:key];
	}
	va_end(args);
	
	NSInteger valueCount = [values count];
	if (valueCount != [keys count]) {
		NSLog(@"set config error : objects and keys don’t have the same number of elements.");
	}
	else {
		NSMutableDictionary *configDictionary = [NSMutableDictionary dictionary];
		for(int index = 0; index < valueCount; index ++) {
			[configDictionary setObject:[values objectAtIndex:index] forKey:[keys objectAtIndex:index]];
		}
		[self archiveDictionary:configDictionary toFilePath:[self settingsFilePath] overwrite:NO];
	}
	
}
/**
 *  获取config中key对应的value
 *
 *  @param key
 *
 *  @return value
 */
- (id)configValueForKey:(NSString *)key {
	if ([NSString isNilOrEmpty:key]) {
		return nil;
	}
	return [self configDictionary][key];
}
/**
 *  获取所有config的dict
 *
 *  @return dict
 */
- (NSDictionary *)configDictionary {
	return [self unarchiveDictionaryFromFilePath:[self settingsFilePath]];
}


/**
 *  设置user的某个key对应的value
 *
 *  @param value
 *  @param key
 */
- (void)setUserConfigValue:(NSObject *)value forKey:(NSString *)key {
	[self setUserConfigWithValuesAndKeys:value, key, nil];
}
/**
 *  设置user的key和value的通用方法
 *  overwrite = no
 *
 *  @param firstObject
 */
- (void)setUserConfigWithValuesAndKeys:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION {
	NSMutableArray *keys = [NSMutableArray array];
	NSMutableArray *values = [NSMutableArray array];
	
	va_list args;
	va_start(args, firstObject);
	for (id value = firstObject; value != nil; value = va_arg(args, id)) {
		id key = va_arg(args, id);
		[values addObject:value];
		[keys addObject:key];
	}
	va_end(args);
	
	NSInteger valueCount = [values count];
	if (valueCount != [keys count]) {
		NSLog(@"set config error : objects and keys don’t have the same number of elements.");
	}
	else {
		NSMutableDictionary *configDictionary = [NSMutableDictionary dictionary];
		for(int index = 0; index < valueCount; index ++) {
			[configDictionary setObject:[values objectAtIndex:index] forKey:[keys objectAtIndex:index]];
		}
		NSLog(@"%@",[self userInfoFilePath]);
		[self archiveDictionary:configDictionary toFilePath:[self userInfoFilePath] overwrite:NO];
	}
}
/**
 *  获取user的某个key
 *
 *  @param key
 *
 *  @return
 */
- (id)userConfigValueForKey:(NSString *)key {
	if ([NSString isNilOrEmpty:key]) {
		return nil;
	}
	return [self userConfigDictionary][key];
}
/**
 *  获取user的整个dict
 *
 *  @return
 */
- (NSDictionary *)userConfigDictionary {
	return [self unarchiveDictionaryFromFilePath:[self userInfoFilePath]];
}


/**
 *  反序列化
 *
 *  @param filePath
 *
 *  @return
 */
- (NSDictionary *)unarchiveDictionaryFromFilePath:(NSString *)filePath {
	NSDictionary *dictionary;
	@try {
		dictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:filePath];
	}
	@catch(NSException *exception) {
		
	}
	@finally {
		
	}
	return dictionary;
}

/**
 *  序列化dict
 *  overwrite = no
 *
 *  @param dicionary
 *  @param filePath
 *
 *  @return
 */
- (BOOL)archiveDictionary:(NSDictionary *)dicionary toFilePath:(NSString *)filePath {
	return [self archiveDictionary:dicionary toFilePath:filePath overwrite:NO];
}

/**
 *  序列化通用方法
 *
 *  @param dicionary
 *  @param filePath
 *  @param overwrite YES-会把相同filePath的dict替换成新的 NO-相同的filePath合并（里面相同key的值会被新的value代替）
 *
 *  @return
 */
- (BOOL)archiveDictionary:(NSDictionary *)dicionary toFilePath:(NSString *)filePath overwrite:(BOOL)overwrite {
	if (overwrite) {
		return [NSKeyedArchiver archiveRootObject:dicionary toFile:filePath];
	}
	else {
		NSMutableDictionary *allDictionary = [NSMutableDictionary dictionaryWithCapacity:[dicionary count]];
		[allDictionary addEntriesFromDictionary:[self unarchiveDictionaryFromFilePath:filePath]];
		[allDictionary addEntriesFromDictionary:dicionary];
		return [NSKeyedArchiver archiveRootObject:allDictionary toFile:filePath];
	}
}


- (id)unarchiveObjectFromFilePath:(NSString *)filePath;
{
	return [self readDataWithFilePath:filePath];
}


- (BOOL)archiveObject:(id)Object toFilePath:(NSString *)filePath;
{
	return [self saveDataWithFilePath:filePath saveObject:Object];
}

- (void)removeObjectFromFilePath:(NSString *)filePath;
{
	BOOL isExit = [[NSFileManager defaultManager] isExecutableFileAtPath:filePath];
	if (isExit) {
		[[NSFileManager defaultManager] removeItemAtPath:filePath error:nil];
	}
}

#pragma mark - 文件管理

- (void)clearCaches {
	NSError *error;
	NSFileManager *fileManager = [NSFileManager defaultManager];
	[fileManager removeItemAtPath:[[StorageManagers sharedInstance] cachesDirectoryPathByUser] error:&error];
	[fileManager removeItemAtPath:[[StorageManagers sharedInstance] cachesDirectoryPathCommon] error:&error];
	
	[self ensureAllDirectories];
}


#pragma mark - 私有方法

- (void)ensureAllDirectories {
	[FileUtils ensureDirectory:[self documentsDirectoryPathCommon]];
	[FileUtils ensureDirectory:[self documentsDirectoryPathByUser]];
	[FileUtils ensureDirectory:[self documentsDirectoryLogPath]];
	[FileUtils ensureDirectory:[self cachesDirectoryPathCommon]];
	[FileUtils ensureDirectory:[self cachesDirectoryPathByUser]];
	[FileUtils ensureDirectory:[self audioDirectoryPath]];
	[FileUtils ensureDirectory:[self videoDirectoryPath]];
	[FileUtils ensureDirectory:[self chatPictureDirectoryPath]];
	[FileUtils ensureDirectory:[self uploadingPictureDirectoryPath]];
}

#define ConfigPlistPath             [[NSBundle mainBundle] pathForResource:@"AppConfig" ofType:@"plist"]
#pragma mark - AppConfig.plist管理

/**
 *  返回项目配置文件里的配置信息
*/
- (NSString *)valueInAppConfig:(NSString *)key {
	if ( ! self.appConfigDictionary) {
		self.appConfigDictionary = [NSDictionary dictionaryWithContentsOfFile:ConfigPlistPath];
	}
	
	if (self.appConfigDictionary[key]) {
		return self.appConfigDictionary[key];
	}
	else {
		return nil;
	}
}




- (BOOL)saveDataWithFilePath:(NSString *)filePath saveObject:(id)saveObject{
	BOOL saved = YES;
	//对于错误信息
	// 路径是否存在
	BOOL isExit = [[NSFileManager defaultManager] isExecutableFileAtPath:filePath];
	if (!isExit) {
		[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
	}
	
	NSError *error;
	//需要写入的字符串
	NSData *data = [NSKeyedArchiver archivedDataWithRootObject:saveObject];
	[data writeToFile:filePath options:NSDataWritingAtomic error:&error];
	if (error) {
		saved = NO;
		NSLog(@"文件写入失败 %@" , [error localizedDescription]);
	}
	return saved;
}


- (id)readDataWithFilePath:(NSString *)filePath {
	NSLog(@"filePath: %@", filePath);
	NSData *fileData = [[NSFileManager defaultManager] contentsAtPath:filePath];
	if (fileData) {
		id object = [NSKeyedUnarchiver unarchiveObjectWithData:fileData];
		return object;
	} else {
		return nil;
	}
}



@end
